package query.select

import ast.expr.*
import ast.limit.SqlLimit
import ast.order.SqlOrderBy
import ast.order.SqlOrderByOption
import ast.statement.select.SqlSelect
import ast.statement.select.SqlSelectItem
import ast.statement.select.SqlSelectQuery
import ast.table.*
import database.DB
import database.DBConnection
import dsl.*
import query.Page
import util.toSqlString
import visitor.checkOLAP
import visitor.getExpr
import visitor.getQueryExpr
import java.math.BigDecimal
import java.sql.Connection
import java.sql.Date
import java.sql.SQLException

/**
 * select语句dsl类
 * @property db DB 数据库类型
 * @property conn Connection? 数据库连接
 * @property isTransaction Boolean 是否是事务
 * @property dbConnection DBConnection? 基础查询类
 * @property sqlSelect SqlSelect select语法树
 * @property joinLeft SqlTableSource join左侧表
 */
class Select(
    var db: DB = DB.MYSQL,
    override var conn: Connection? = null,
    override var isTransaction: Boolean = false,
    override var dbConnection: DBConnection? = null
) :
    SelectQueryImpl() {
    constructor(db: DB) : this(db, null, false, null)

    private var sqlSelect = SqlSelect()

    private lateinit var joinLeft: SqlTableSource

    init {
        sqlSelect.addSelectItem(SqlAllColumnExpr())
    }

    /**
     * 获取sql语法树
     * @return SqlSelect sql语法树
     */
    fun getSqlSelect() = this.sqlSelect

    /**
     * from子句
     * 例如：Select().from("table1", "t1")
     * @param table String 表名
     * @param alias String? 表别名（可不传）
     * @return Select 查询dsl
     */
    fun from(table: String, alias: String? = null): Select {
        val from = SqlIdentifierTableSource(table)
        from.alias = alias
        joinLeft = from
        sqlSelect.from = from
        return this
    }

    /**
     * from子句
     * 例如：Select() from "t1"
     * @param table String 表名
     * @return Select 查询dsl
     */
    infix fun from(table: String): Select {
        return from(table, null)
    }

    /**
     * from子句（子查询）
     * 例如：Select().from(Select() from "table1", "t1")
     * @param select SelectQuery 子查询dsl
     * @param alias String? 表别名（可不传）
     * @return Select 查询dsl
     */
    fun from(select: SelectQuery, alias: String? = null): Select {
        val from = SqlSubQueryTableSource(select.getSelect(), alias)
        joinLeft = from
        sqlSelect.from = from
        return this
    }

    /**
     * from子句（子查询）
     * 例如：Select() from (Select() from "table1", "t1")
     * @param select SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun from(select: SelectQuery): Select {
        return from(select, null)
    }

    /**
     * from lateral子句
     * 例如：Select() fromLateral (Select() from "table1", "t1")
     * @param select SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun fromLateral(select: SelectQuery): Select {
        val from = SqlSubQueryTableSource(select.getSelect(), isLateral = true)
        joinLeft = from
        sqlSelect.from = from
        return this
    }

    /**
     * from子句
     * 例如：Select().from(Table, "t1")
     * @param table T 实体类伴生对象名
     * @param alias String? 表别名（可不传）
     * @return Select 查询dsl
     */
    fun <T : TableSchema> from(table: T, alias: String? = null): Select {
        return from(table.tableName, alias)
    }

    /**
     * from子句
     * 例如：Select() from Table
     * @param table T 实体类伴生对象名
     * @return Select 查询dsl
     */
    infix fun <T : TableSchema> from(table: T): Select {
        return from(table.tableName, null)
    }

    /**
     * 给表起别名（如果有join，那么会给最近的一张表起别名）
     * 例如：Select() from Table alias "t1"
     * @param name String 表别名
     * @return Select 查询dsl
     */
    infix fun alias(name: String): Select {
        val from = this.sqlSelect.from
        if (from is SqlJoinTableSource) {
            from.right.alias = name
        } else {
            from?.alias = name
        }

        return this
    }

    /**
     * 给表和列起别名（如果有join，那么会给最近的一张表起别名），会生成FROM table_name table_alias(column1_alias, column2_alias) 形式的sql
     * 例如：Select().from(Table).alias("t1", "c1", "c2")
     * @param tableName String 表别名
     * @param columnName Array<out String> 列别名
     * @return Select 查询dsl
     */
    fun alias(tableName: String, vararg columnName: String): Select {
        val from = this.sqlSelect.from
        if (from is SqlJoinTableSource) {
            from.right.alias = tableName
            from.right.columnAliasNames.addAll(columnName.toList())
        } else {
            from?.alias = tableName
            from?.columnAliasNames?.addAll(columnName.toList())
        }

        return this
    }

    /**
     * distinct子句
     * @return Select 查询dsl
     */
    fun distinct(): Select {
        sqlSelect.distinct = true
        return this
    }

    /**
     * select子句
     * 例如：Select().select(column("c1"), column("c2"))
     * @param query Array<out Query> 查询的表达式列表
     * @return Select 查询dsl
     */
    fun select(vararg query: Query): Select {
        if (this.sqlSelect.selectList.size == 1 && this.sqlSelect.selectList[0].expr is SqlAllColumnExpr) {
            this.sqlSelect.selectList.clear()
        }
        query.forEach {
            val queryExpr = getQueryExpr(it, this.db)
            sqlSelect.addSelectItem(queryExpr.expr, queryExpr.alias)
        }
        return this
    }

    /**
     * operator invoke
     * @param query List<Query>
     * @return Select
     */
    infix operator fun invoke(query: List<Query>): Select {
        return select(*query.toTypedArray())
    }

    /**
     * operator invoke
     * @param query Query
     * @return Select
     */
    infix operator fun invoke(query: Query): Select {
        return select(*arrayOf(query))
    }

    /**
     * select子句（中缀调用）
     * 例如：Select() select listOf(column("c1"), column("c2"))
     * @param query List<Query> 查询的表达式列表
     * @return Select 查询dsl
     */
    infix fun select(query: List<Query>): Select {
        return select(*query.toTypedArray())
    }

    /**
     * select子句（中缀调用）
     * 例如：Select() select count()
     * @param query Query 查询的表达式
     * @return Select 查询dsl
     */
    infix fun select(query: Query): Select {
        return select(*arrayOf(query))
    }

    /**
     * select distinct子句
     * @param query List<Query> 查询的表达式列表
     * @return Select 查询dsl
     */
    infix fun selectDistinct(query: List<Query>): Select {
        distinct()
        return select(*query.toTypedArray())
    }

    /**
     * select distinct子句（中缀调用）
     * @param query Query 查询的表达式
     * @return Select 查询dsl
     */
    infix fun selectDistinct(query: Query): Select {
        distinct()
        return select(*arrayOf(query))
    }

    /**
     * select *（后续如果还有调用其他select函数，会替换掉查询列表里的*）
     * 例如：Select().select()
     * @return Select 查询dsl
     */
    fun select(): Select {
        if (this.sqlSelect.selectList.size == 1 && this.sqlSelect.selectList[0].expr is SqlAllColumnExpr) {
            this.sqlSelect.selectList.clear()
        }
        sqlSelect.addSelectItem(SqlAllColumnExpr())
        return this
    }

    /**
     * select子句（字段名中如果有.会被识别为表名+字段名的格式，*会被识别为通配符）
     * 例如：Select().select("c1", "t1.c2")
     * @param columns Array<out String> 字段名
     * @return Select 查询dsl
     */
    fun select(vararg columns: String): Select {
        if (this.sqlSelect.selectList.size == 1 && this.sqlSelect.selectList[0].expr is SqlAllColumnExpr) {
            this.sqlSelect.selectList.clear()
        }
        columns.forEach {
            val trim = it.trim()

            val split = trim.split(" ")
            val alias = if (trim.contains(" ")) {
                split.last()
            } else {
                null
            }
            val column = split.first()

            if (column.contains(".")) {
                val splitDot = column.split(".")
                val expr = if (splitDot.last().contains("*")) {
                    SqlAllColumnExpr(splitDot.first())
                } else {
                    SqlPropertyExpr(splitDot.first(), splitDot.last())
                }
                sqlSelect.addSelectItem(expr, alias)
            } else {
                val expr = if (column.contains("*")) {
                    SqlAllColumnExpr()
                } else {
                    SqlIdentifierExpr(column)
                }
                sqlSelect.addSelectItem(expr, alias)
            }
        }
        return this
    }

    /**
     * where子句（如果有多个where调用，会使用AND拼接条件）
     * 例如：Select() from Table where (Table.c1 eq 1)
     * @param query Query where条件中的表达式
     * @return Select 查询dsl
     */
    infix fun where(query: Query): Select {
        sqlSelect.addCondition(getQueryExpr(query, this.db).expr)
        return this
    }

    /**
     * where子句（第一个参数的lambda返回值为true时，表达式会被拼接到where子句中）
     * @param test Function0<Boolean> 检测表达式
     * @param query Query where条件中的表达式
     * @return Select 查询dsl
     */
    fun where(test: () -> Boolean, query: Query): Select {
        if (test()) {
            where(query)
        }
        return this
    }

    /**
     * where子句（第一个参数的值为true时，表达式会被拼接到where子句中）
     * @param test Boolean 检测表达式
     * @param query Query where条件中的表达式
     * @return Select 查询dsl
     */
    fun where(test: Boolean, query: Query): Select {
        if (test) {
            where(query)
        }
        return this
    }

    /**
     * having子句（使用方式请参考where）
     * @param query Query having条件中的表达式
     * @return Select 查询dsl
     */
    infix fun having(query: Query): Select {
        sqlSelect.addHaving(getQueryExpr(query, this.db).expr)
        return this
    }

    /**
     * @param specification SqlOrderByOption
     * @param columns Array<out Query>
     */
    private fun orderBy(specification: SqlOrderByOption, vararg columns: Query) {
        columns.forEach {
            val item = SqlOrderBy(getQueryExpr(it, this.db).expr, specification)
            sqlSelect.orderBy.add(item)
        }
    }

    /**
     * order by子句（正序），与其他order by类函数可以组合调用
     * 例如：Select().from(Table).orderByAsc("c1", "c2")
     * @param columns Array<out String> 字段名列表
     * @return Select 查询dsl
     */
    fun orderByAsc(vararg columns: String): Select {
        orderBy(SqlOrderByOption.ASC, *columns.map { column(it) }.toTypedArray())
        return this
    }

    /**
     * order by子句（正序），与其他order by类函数可以组合调用
     * 例如：Select().from(Table).orderByAsc(column("c1"), column("c2"))
     * @param columns Array<out Query> 待排序的表达式列表
     * @return Select 查询dsl
     */
    fun orderByAsc(vararg columns: Query): Select {
        orderBy(SqlOrderByOption.ASC, *columns)
        return this
    }


    /**
     * 中缀调用order by子句（正序），与其他order by类函数可以组合调用
     * 例如：Select() from Table orderByAsc listOf(column("c1"), column("c2"))
     * @param columns List<Query> 待排序的表达式列表
     * @return Select 查询dsl
     */
    infix fun orderByAsc(columns: List<Query>): Select {
        return orderByAsc(*columns.toTypedArray())
    }

    /**
     * 中缀调用order by子句（正序），与其他order by类函数可以组合调用
     * 例如：Select() from Table orderByAsc column("c1")
     * @param column Query 待排序的表达式
     * @return Select 查询dsl
     */
    infix fun orderByAsc(column: Query): Select {
        return orderByAsc(*arrayOf(column))
    }

    /**
     * order by子句（倒序），与其他order by类函数可以组合调用
     * 例如：Select().from(Table).orderByDesc("c1", "c2")
     * @param columns Array<out String> 字段名列表
     * @return Select 查询dsl
     */
    fun orderByDesc(vararg columns: String): Select {
        orderBy(SqlOrderByOption.DESC, *columns.map { column(it) }.toTypedArray())
        return this
    }

    /**
     * order by子句（倒序），与其他order by类函数可以组合调用
     * 例如：Select().from(Table).orderByDesc(column("c1"), column("c2"))
     * @param columns Array<out Query> 待排序的表达式列表
     * @return Select 查询dsl
     */
    fun orderByDesc(vararg columns: Query): Select {
        orderBy(SqlOrderByOption.DESC, *columns)
        return this
    }

    /**
     * 中缀调用order by子句（倒序），与其他order by类函数可以组合调用
     * 例如：Select() from Table orderByDesc listOf(column("c1"), column("c2"))
     * @param columns List<Query> 待排序的表达式列表
     * @return Select 查询dsl
     */
    infix fun orderByDesc(columns: List<Query>): Select {
        return orderByDesc(*columns.toTypedArray())
    }

    /**
     * 中缀调用order by子句（倒序），与其他order by类函数可以组合调用
     * 例如：Select() from Table orderByDesc column("c1")
     * @param column Query 待排序的表达式
     * @return Select 查询dsl
     */
    infix fun orderByDesc(column: Query): Select {
        return orderByDesc(*arrayOf(column))
    }

    /**
     * order by子句（使用表达式类型的.asc()或.desc()生成排序规则传入）
     * 例如：Select().from(Table).orderBy(Table.c1.asc(), Table.c2.desc())
     * @param orderBy Array<out OrderBy> 排序规则列表
     * @return Select 查询dsl
     */
    fun orderBy(vararg orderBy: OrderBy): Select {
        orderBy.forEach {
            orderBy(it.order, it.query)
        }
        return this
    }

    /**
     * 中缀调用order by子句（使用表达式类型的.asc()或.desc()生成排序规则传入）
     * 例如：Select() from Table orderBy listOf(Table.c1.asc(), Table.c2.desc())
     * @param orderByList List<OrderBy> 排序规则列表
     * @return Select 查询dsl
     */
    infix fun orderBy(orderByList: List<OrderBy>): Select {
        return orderBy(*orderByList.toTypedArray())
    }

    /**
     * 中缀调用order by子句（使用表达式类型的.asc()或.desc()生成排序规则传入）
     * 例如：Select() from Table orderBy Table.c1.asc()
     * @param orderBy List<OrderBy> 排序规则
     * @return Select 查询dsl
     */
    infix fun orderBy(orderBy: OrderBy): Select {
        return orderBy(*arrayOf(orderBy))
    }

    /**
     * limit子句
     * 例如：Select().from(Table).limit(10, 100)
     * @param count Int 条数
     * @param offset Int 偏移量
     * @return Select 查询dsl
     */
    fun limit(count: Int, offset: Int): Select {
        val sqlLimit = SqlLimit(count, offset)
        sqlSelect.limit = sqlLimit
        return this
    }

    /**
     * 中缀调用limit子句（如果后续没有offset函数调用，那么偏移量为0）
     * 例如：Select() from Table limit 10
     * @param count Int 条数
     * @return Select 查询dsl
     */
    infix fun limit(count: Int): Select {
        return limit(count, 0)
    }

    /**
     * 中缀调用offset子句（需要保证之前有limit函数调用，否则会产生异常）
     * 例如：Select() from Table limit 10 offset 100
     * @param offset Int 偏移量
     * @return Select 查询dsl
     */
    infix fun offset(offset: Int): Select {
        this.sqlSelect.limit?.offset = offset
        return this
    }

    /**
     * group by子句
     * 例如：Select().from(Table).groupBy(Table.c1, Table.c2)
     * @param columns Array<out Query> 分组表达式列表
     * @return Select 查询dsl
     */
    fun groupBy(vararg columns: Query): Select {
        columns.forEach {
            val expr = getQueryExpr(it, this.db).expr
            sqlSelect.groupBy.add(expr)
        }
        return this
    }

    /**
     * 中缀调用group by子句
     * 例如：Select() from Table groupBy Table.c1
     * @param column Query 分组表达式
     * @return Select 查询dsl
     */
    infix fun groupBy(column: Query): Select {
        return groupBy(*arrayOf(column))
    }

    /**
     * 中缀调用group by子句
     * 例如：Select() from Table groupBy listOf(Table.c1, Table.c2)
     * @param columns List<Query> 分组表达式列表
     * @return Select 查询dsl
     */
    infix fun groupBy(columns: List<Query>): Select {
        return groupBy(*columns.toTypedArray())
    }

    /**
     * group by子句
     * 例如：Select().from(Table).groupBy("c1", "c2")
     * @param columns Array<out String> 分组列名列表
     * @return Select 查询dsl
     */
    fun groupBy(vararg columns: String): Select {
        val query = columns.map { QueryColumn(it) }.toTypedArray()
        return groupBy(*query)
    }

    /**
     * @param table String
     * @param joinType SqlJoinType
     * @return Select
     */
    private fun join(
        table: String,
        joinType: SqlJoinType
    ): Select {
        val join = SqlJoinTableSource(joinLeft, joinType, SqlIdentifierTableSource(table))
        sqlSelect.from = join
        joinLeft = join
        return this
    }

    /**
     * @param table SelectQuery
     * @param joinType SqlJoinType
     * @param isLateral Boolean
     * @return Select
     */
    private fun join(
        table: SelectQuery,
        joinType: SqlJoinType,
        isLateral: Boolean = false
    ): Select {
        val join =
            SqlJoinTableSource(joinLeft, joinType, SqlSubQueryTableSource(table.getSelect(), isLateral = isLateral))
        sqlSelect.from = join
        joinLeft = join
        return this
    }

    /**
     * on子句（需要保证之前调用了join类函数，否则会产生异常）
     * 例如：Select() from Table1 join Table2 on (Table1.c1 eq Table2.c2)
     * @param on Query 连接条件表达式
     * @return Select 查询dsl
     */
    infix fun on(on: Query): Select {
        val from = this.sqlSelect.from
        if (from is SqlJoinTableSource) {
            from.on = getQueryExpr(on, this.db).expr
        }
        return this
    }

    /**
     * join子句
     * 例如：Select() from Table1 join "t2"
     * @param table String 表名
     * @return Select 查询dsl
     */
    infix fun join(table: String): Select {
        return join(table, SqlJoinType.JOIN)
    }

    /**
     * join子句
     * 例如：Select() from Table1 join Table2
     * @param table TableSchema 实体类伴生对象名
     * @return Select 查询dsl
     */
    infix fun join(table: TableSchema): Select {
        return join(table.tableName, SqlJoinType.JOIN)
    }

    /**
     * join子句（子查询）
     * 例如：Select() from Table1 join (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun join(table: SelectQuery): Select {
        return join(table, SqlJoinType.JOIN)
    }

    /**
     * join lateral子句
     * 例如：Select() from Table1 joinLateral (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun joinLateral(table: SelectQuery): Select {
        return join(table, SqlJoinType.JOIN, true)
    }

    /**
     * left join子句
     * 例如：Select() from Table1 leftJoin "t2"
     * @param table String 表名
     * @return Select 查询dsl
     */
    infix fun leftJoin(table: String): Select {
        return join(table, SqlJoinType.LEFT_JOIN)
    }

    /**
     * left join子句
     * 例如：Select() from Table1 leftJoin Table2
     * @param table TableSchema 实体类伴生对象名
     * @return Select 查询dsl
     */
    infix fun leftJoin(table: TableSchema): Select {
        return join(table.tableName, SqlJoinType.LEFT_JOIN)
    }

    /**
     * left join子句（子查询）
     * 例如：Select() from Table1 leftJoin (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun leftJoin(table: SelectQuery): Select {
        return join(table, SqlJoinType.LEFT_JOIN)
    }

    /**
     * left join lateral子句
     * 例如：Select() from Table1 leftJoinLateral (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun leftJoinLateral(table: SelectQuery): Select {
        return join(table, SqlJoinType.LEFT_JOIN, true)
    }

    /**
     * right join子句
     * 例如：Select() from Table1 rightJoin "t2"
     * @param table String 表名
     * @return Select 查询dsl
     */
    infix fun rightJoin(table: String): Select {
        return join(table, SqlJoinType.RIGHT_JOIN)
    }

    /**
     * right join子句
     * 例如：Select() from Table1 rightJoin Table2
     * @param table TableSchema 实体类伴生对象名
     * @return Select 查询dsl
     */
    infix fun rightJoin(table: TableSchema): Select {
        return join(table.tableName, SqlJoinType.RIGHT_JOIN)
    }

    /**
     * right join子句（子查询）
     * 例如：Select() from Table1 rightJoin (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun rightJoin(table: SelectQuery): Select {
        return join(table, SqlJoinType.RIGHT_JOIN)
    }

    /**
     * right join lateral子句
     * 例如：Select() from Table1 rightJoinLateral (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun rightJoinLateral(table: SelectQuery): Select {
        return join(table, SqlJoinType.RIGHT_JOIN, true)
    }

    /**
     * inner join子句
     * 例如：Select() from Table1 innerJoin "t2"
     * @param table String 表名
     * @return Select 查询dsl
     */
    infix fun innerJoin(table: String): Select {
        return join(table, SqlJoinType.INNER_JOIN)
    }

    /**
     * inner join子句
     * 例如：Select() from Table1 innerJoin Table2
     * @param table TableSchema 实体类伴生对象名
     * @return Select 查询dsl
     */
    infix fun innerJoin(table: TableSchema): Select {
        return join(table.tableName, SqlJoinType.INNER_JOIN)
    }

    /**
     * inner join子句（子查询）
     * 例如：Select() from Table1 innerJoin (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun innerJoin(table: SelectQuery): Select {
        return join(table, SqlJoinType.INNER_JOIN)
    }

    /**
     * inner join lateral子句
     * 例如：Select() from Table1 innerJoinLateral (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun innerJoinLateral(table: SelectQuery): Select {
        return join(table, SqlJoinType.INNER_JOIN, true)
    }

    /**
     * cross join子句
     * 例如：Select() from Table1 crossJoin "t2"
     * @param table String 表名
     * @return Select 查询dsl
     */
    infix fun crossJoin(table: String): Select {
        return join(table, SqlJoinType.CROSS_JOIN)
    }

    /**
     * cross join子句
     * 例如：Select() from Table1 crossJoin Table2
     * @param table TableSchema 实体类伴生对象名
     * @return Select 查询dsl
     */
    infix fun crossJoin(table: TableSchema): Select {
        return join(table.tableName, SqlJoinType.CROSS_JOIN)
    }

    /**
     * cross join子句（子查询）
     * 例如：Select() from Table1 crossJoin (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun crossJoin(table: SelectQuery): Select {
        return join(table, SqlJoinType.CROSS_JOIN)
    }

    /**
     * cross join lateral子句
     * 例如：Select() from Table1 crossJoinLateral (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun crossJoinLateral(table: SelectQuery): Select {
        return join(table, SqlJoinType.CROSS_JOIN, true)
    }

    /**
     * full join子句
     * 例如：Select() from Table1 fullJoin "t2"
     * @param table String 表名
     * @return Select 查询dsl
     */
    infix fun fullJoin(table: String): Select {
        return join(table, SqlJoinType.FULL_JOIN)
    }

    /**
     * full join子句
     * 例如：Select() from Table1 fullJoin Table2
     * @param table TableSchema 实体类伴生对象名
     * @return Select 查询dsl
     */
    infix fun fullJoin(table: TableSchema): Select {
        return join(table.tableName, SqlJoinType.FULL_JOIN)
    }

    /**
     * full join子句（子查询）
     * 例如：Select() from Table1 fullJoin (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun fullJoin(table: SelectQuery): Select {
        return join(table, SqlJoinType.FULL_JOIN)
    }

    /**
     * full join lateral子句
     * 例如：Select() from Table1 fullJoinLateral (Select() from Table2)
     * @param table SelectQuery 子查询dsl
     * @return Select 查询dsl
     */
    infix fun fullJoinLateral(table: SelectQuery): Select {
        return join(table, SqlJoinType.FULL_JOIN, true)
    }

    /**
     * 查询加锁
     * @return Select 查询dsl
     */
    fun forUpdate(): Select {
        checkOLAP(this.db)

        this.sqlSelect.forUpdate = true
        return this
    }

    /**
     * 生成sql语句
     * @return String sql语句
     */
    override fun sql(): String {
        if (sqlSelect.selectList.isEmpty()) {
            select()
        }

        return toSqlString(sqlSelect, db)
    }

    /**
     * 获取查询总数sql（会复制一个查询副本，并去掉limit与order by信息）
     * @return String sql语句
     */
    fun fetchCountSql(): String {
        val selectCopy = this.sqlSelect.copy(selectList = mutableListOf(), orderBy = mutableListOf(), limit = null)
        selectCopy.selectList.clear()
        selectCopy.orderBy.clear()
        selectCopy.addSelectItem(getQueryExpr(count(), this.db).expr, "count")

        return toSqlString(selectCopy, db)
    }

    /**
     * 获取分页查询sql（会复制一个查询副本，并根据参数替换limit信息）
     * @param pageSize Int 一页的条数
     * @param pageNumber Int 页码
     * @return String sql语句
     */
    fun pageSql(pageSize: Int, pageNumber: Int): String {
        if (sqlSelect.selectList.isEmpty()) {
            select()
        }

        val offset = if (pageNumber <= 1) {
            0
        } else {
            pageSize * (pageNumber - 1)
        }
        val limit = SqlLimit(pageSize, offset)

        val selectCopy = getSqlSelect().copy(limit = limit)

        return toSqlString(selectCopy, db)
    }

    /**
     * 获取sql语法树
     * @return SqlSelectQuery sql语法树
     */
    override fun getSelect(): SqlSelectQuery {
        return this.sqlSelect
    }

    /**
     * 获取数据库类型
     * @return DB 数据库类型
     */
    override fun getDbType(): DB {
        return this.db
    }

    /**
     * 获取一条数据
     * @param bind Function1<List<Map<String, Any?>>, List<T>> 绑定方式
     * @return T? 查询结果
     */
    fun <T> find(bind: (List<Map<String, Any?>>) -> List<T>): T? {
        val limit = SqlLimit(1, sqlSelect.limit?.offset ?: 0)
        val selectCopy = this.sqlSelect.copy(limit = limit)
        val sql = toSqlString(selectCopy, db)

        val list = query(sql, isTransaction, conn!!, dbConnection)

        if (list.isEmpty()) {
            return null
        }

        val bindList = bind(list)

        return bindList[0]
    }

    /**
     * 获取一条数据
     * @param clazz Class<T> 实体类的java class
     * @return T? 查询结果
     */
    fun <T : Any> find(clazz: Class<T>): T? {
        return find { bind(clazz, it) }
    }

    /**
     * 获取一条数据
     * @return T? 查询结果
     */
    inline fun <reified T> find(): T? {
        return find { bind(it) }
    }

    /**
     * 获取一条数据
     * @return Map<String, Any?>? 查询结果
     */
    fun findMap(): Map<String, Any?>? {
        return find { it }
    }

    /**
     * 获取总数（会复制一个查询副本，并去掉limit与order by信息）
     * @return Long 总数
     */
    override fun fetchCount(): Long {
        val selectCopy = this.sqlSelect.copy(selectList = mutableListOf(), orderBy = mutableListOf(), limit = null)
        selectCopy.selectList.clear()
        selectCopy.orderBy.clear()
        selectCopy.addSelectItem(getQueryExpr(count(), this.db).expr, "count")

        val sql = toSqlString(selectCopy, db)

        val result = query(sql, isTransaction, conn!!, dbConnection)

        return result[0]["count"] as Long
    }

    /**
     * 获取分页结果（会复制一个查询副本，并根据参数替换limit信息）
     * @param pageSize Int 一页的条数
     * @param pageNumber Int 页码
     * @param needCount Boolean 是否需要查询count信息
     * @param bind Function1<List<Map<String, Any?>>, List<T>> 绑定方式
     * @return Page<T> 分页结果
     */
    fun <T> page(
        pageSize: Int,
        pageNumber: Int,
        needCount: Boolean = true,
        bind: (List<Map<String, Any?>>) -> List<T>
    ): Page<T> {
        val data = if (pageSize == 0) {
            listOf()
        } else {
            val offset = if (pageNumber <= 1) {
                0
            } else {
                pageSize * (pageNumber - 1)
            }
            val limit = SqlLimit(pageSize, offset)

            val selectCopy = getSqlSelect().copy(limit = limit)

            val sql = toSqlString(selectCopy, db)

            val list = query(sql, isTransaction, conn!!, dbConnection)
            bind(list)
        }

        val totalCount = if (needCount) {
            fetchCount()
        } else {
            0L
        }

        val totalPage = if (totalCount == 0L || pageSize == 0) {
            0L
        } else {
            if (totalCount % pageSize == 0L) {
                totalCount / pageSize
            } else {
                totalCount / pageSize + 1
            }
        }

        return Page(totalPage, totalCount, data)
    }

    /**
     * 获取分页结果（会复制一个查询副本，并根据参数替换limit信息）
     * @param clazz Class<T> 实体类的java class
     * @param pageSize Int 一页的条数
     * @param pageNumber Int 页码
     * @param needCount Boolean 是否需要查询count信息
     * @return Page<T> 分页结果
     */
    fun <T : Any> page(clazz: Class<T>, pageSize: Int, pageNumber: Int, needCount: Boolean = true): Page<T> {
        return page(pageSize, pageNumber, needCount) { bind(clazz, it) }
    }

    /**
     * 获取分页结果（会复制一个查询副本，并根据参数替换limit信息）
     * @param pageSize Int 一页的条数
     * @param pageNumber Int 页码
     * @param needCount Boolean 是否需要查询count信息
     * @return Page<T> 分页结果
     */
    inline fun <reified T> page(pageSize: Int, pageNumber: Int, needCount: Boolean = true): Page<T> {
        return page(pageSize, pageNumber, needCount) { bind(it) }
    }

    /**
     * 获取分页结果（会复制一个查询副本，并根据参数替换limit信息）
     * @param pageSize Int 一页的条数
     * @param pageNumber Int 页码
     * @param needCount Boolean 是否需要查询count信息
     * @return Page<T> 分页结果
     */
    fun pageMap(pageSize: Int, pageNumber: Int, needCount: Boolean = true): Page<Map<String, Any?>> {
        return page(pageSize, pageNumber, needCount) { it }
    }

    /**
     * @param result List<Map<String, Any?>>
     * @param sort OrderBy
     * @return List<Map<String, Any?>>
     */
    private fun turnPage(result: List<Map<String, Any?>>, sort: OrderBy): List<Map<String, Any?>> {
        val sortName = when (sort.query) {
            is QueryColumn -> sort.query.column
            is QueryTableColumn -> sort.query.column
            else -> throw SQLException("此分页方式的排序需要使用列名")
        }

        val sortList = result.map {
            val sortItem = when (val s = it[sortName]) {
                is Int -> s
                is Long -> s
                is Short -> s
                is Byte -> s
                is Char -> s
                is Float -> s
                is Double -> s
                is BigDecimal -> s
                is String -> s
                is Boolean -> s
                is Date -> s
                else -> throw TypeCastException("字段类型不可用来排序")
            }

            sortName to sortItem
        }

        val sortedList = if (sort.order == SqlOrderByOption.ASC) {
            sortList.sortedWith(compareBy { it.second })
        } else {
            sortList.sortedWith(compareByDescending { it.second })
        }

        return sortedList.map {
            val filterList = result.filter { item -> item[sortName] == it.second }
            filterList[0]
        }
    }

    /**
     * 根据排序字段游标排序（首页）
     * @param sort OrderBy 排序规则
     * @param pageSize Int 一页的条数
     * @param bind Function1<List<Map<String, Any?>>, List<T>> 绑定方式
     * @return List<T> 查询结果
     */
    fun <T> firstPage(sort: OrderBy, pageSize: Int, bind: (List<Map<String, Any?>>) -> List<T>): List<T> {
        val selectCopy = getSqlSelect().copy()
        selectCopy.orderBy.clear()
        selectCopy.orderBy.add(SqlOrderBy(getQueryExpr(sort.query, this.db).expr, sort.order))
        selectCopy.limit = SqlLimit(pageSize, 0)
        val list = query(toSqlString(selectCopy, db), isTransaction, conn!!, dbConnection)
        return bind(list)
    }

    /**
     * 根据排序字段游标排序（首页）
     * @param clazz Class<T> 实体类java class
     * @param sort OrderBy 排序规则
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    fun <T : Any> firstPage(clazz: Class<T>, sort: OrderBy, pageSize: Int): List<T> {
        return firstPage(sort, pageSize) { bind(clazz, it) }
    }

    /**
     * 根据排序字段游标排序（首页）
     * @param sort OrderBy 排序规则
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    inline fun <reified T> firstPage(sort: OrderBy, pageSize: Int): List<T> {
        return firstPage(sort, pageSize) { bind(it) }
    }

    /**
     * 根据排序字段游标排序（首页）
     * @param sort OrderBy 排序规则
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    fun firstPageMap(sort: OrderBy, pageSize: Int): List<Map<String, Any?>> {
        return firstPage(sort, pageSize) { it }
    }

    /**
     * 根据排序字段游标排序（尾页）
     * @param sort OrderBy 排序规则
     * @param pageSize Int 一页的条数
     * @param bind Function1<List<Map<String, Any?>>, List<T>> 绑定方式
     * @return List<T> 查询结果
     */
    fun <T> lastPage(sort: OrderBy, pageSize: Int, bind: (List<Map<String, Any?>>) -> List<T>): List<T> {
        val selectCopy = getSqlSelect().copy()
        selectCopy.orderBy.clear()
        selectCopy.orderBy.add(SqlOrderBy(getQueryExpr(sort.query, this.db).expr, sort.order.turn()))
        selectCopy.limit = SqlLimit(pageSize, 0)
        val list = query(toSqlString(selectCopy, db), isTransaction, conn!!, dbConnection)

        if (list.isEmpty()) {
            return listOf()
        }

        return bind(turnPage(list, sort))
    }

    /**
     * 根据排序字段游标排序（尾页）
     * @param sort OrderBy 排序规则
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    fun <T : Any> lastPage(clazz: Class<T>, sort: OrderBy, pageSize: Int): List<T> {
        return lastPage(sort, pageSize) { bind(clazz, it) }
    }

    /**
     * 根据排序字段游标排序（尾页）
     * @param sort OrderBy 排序规则
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    inline fun <reified T> lastPage(sort: OrderBy, pageSize: Int): List<T> {
        return lastPage(sort, pageSize) { bind(it) }
    }

    /**
     * 根据排序字段游标排序（尾页）
     * @param sort OrderBy 排序规则
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    fun lastPageMap(sort: OrderBy, pageSize: Int): List<Map<String, Any?>> {
        return lastPage(sort, pageSize) { it }
    }

    /**
     * 根据排序字段游标排序（上一页）
     * @param sort OrderBy 排序规则
     * @param value Any 当前页第一条数据排序字段的值
     * @param pageSize Int 一页的条数
     * @param bind Function1<List<Map<String, Any?>>, List<T>> 绑定方式
     * @return List<T> 查询结果
     */
    fun <T> previousPage(
        sort: OrderBy,
        value: Any,
        pageSize: Int,
        bind: (List<Map<String, Any?>>) -> List<T>
    ): List<T> {
        val selectCopy = getSqlSelect().copy()
        selectCopy.orderBy.clear()
        selectCopy.orderBy.add(SqlOrderBy(getQueryExpr(sort.query, this.db).expr, sort.order.turn()))
        selectCopy.limit = SqlLimit(pageSize, 0)
        val operator = if (sort.order == SqlOrderByOption.ASC) {
            SqlBinaryOperator.LT
        } else {
            SqlBinaryOperator.GT
        }
        selectCopy.addCondition(SqlBinaryExpr(getQueryExpr(sort.query, this.db).expr, operator, getExpr(value)))
        val list = query(toSqlString(selectCopy, db), isTransaction, conn!!, dbConnection)

        if (list.isEmpty()) {
            return listOf()
        }

        return bind(turnPage(list, sort))
    }

    /**
     * 根据排序字段游标排序（上一页）
     * @param clazz Class<T> 实体类java class
     * @param sort OrderBy 排序规则
     * @param value Any 当前页第一条数据排序字段的值
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    fun <T : Any> previousPage(clazz: Class<T>, sort: OrderBy, value: Any, pageSize: Int): List<T> {
        return previousPage(sort, value, pageSize) { bind(clazz, it) }
    }

    /**
     * 根据排序字段游标排序（上一页）
     * @param sort OrderBy 排序规则
     * @param value Any 当前页第一条数据排序字段的值
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    inline fun <reified T> previousPage(sort: OrderBy, value: Any, pageSize: Int): List<T> {
        return previousPage(sort, value, pageSize) { bind(it) }
    }

    /**
     * 根据排序字段游标排序（上一页）
     * @param sort OrderBy 排序规则
     * @param value Any 当前页第一条数据排序字段的值
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    fun previousPageMap(sort: OrderBy, value: Any, pageSize: Int): List<Map<String, Any?>> {
        return previousPage(sort, value, pageSize) { it }
    }

    /**
     * 根据排序字段游标排序（下一页）
     * @param sort OrderBy 排序规则
     * @param value Any 当前页最后一条数据排序字段的值
     * @param pageSize Int 一页的条数
     * @param bind Function1<List<Map<String, Any?>>, List<T>> 绑定方式
     * @return List<T> 查询结果
     */
    fun <T> nextPage(sort: OrderBy, value: Any, pageSize: Int, bind: (List<Map<String, Any?>>) -> List<T>): List<T> {
        val selectCopy = getSqlSelect().copy()
        selectCopy.orderBy.clear()
        selectCopy.orderBy.add(SqlOrderBy(getQueryExpr(sort.query, this.db).expr, sort.order))
        selectCopy.limit = SqlLimit(pageSize, 0)
        val operator = if (sort.order == SqlOrderByOption.ASC) {
            SqlBinaryOperator.GT
        } else {
            SqlBinaryOperator.LT
        }
        selectCopy.addCondition(SqlBinaryExpr(getQueryExpr(sort.query, this.db).expr, operator, getExpr(value)))
        val list = query(toSqlString(selectCopy, db), isTransaction, conn!!, dbConnection)
        return bind(list)
    }

    /**
     * 根据排序字段游标排序（下一页）
     * @param clazz Class<T> 实体类java class
     * @param sort OrderBy 排序规则
     * @param value Any 当前页最后一条数据排序字段的值
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    fun <T : Any> nextPage(clazz: Class<T>, sort: OrderBy, value: Any, pageSize: Int): List<T> {
        return nextPage(sort, value, pageSize) { bind(clazz, it) }
    }

    /**
     * 根据排序字段游标排序（下一页）
     * @param sort OrderBy 排序规则
     * @param value Any 当前页最后一条数据排序字段的值
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    inline fun <reified T> nextPage(sort: OrderBy, value: Any, pageSize: Int): List<T> {
        return nextPage(sort, value, pageSize) { bind(it) }
    }

    /**
     * 根据排序字段游标排序（下一页）
     * @param sort OrderBy 排序规则
     * @param value Any 当前页最后一条数据排序字段的值
     * @param pageSize Int 一页的条数
     * @return List<T> 查询结果
     */
    fun nextPageMap(sort: OrderBy, value: Any, pageSize: Int): List<Map<String, Any?>> {
        return nextPage(sort, value, pageSize) { it }
    }
}